home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-08 | 30.0 KB | 948 lines | [TEXT/KAHL] |
- //------------------------- © 1994-1995 by James G. Stout ---------------------------
- // File : cdefTab.c
- // Date : July 24, 1994
- // Author : Jim Stout
- // Purpose : A CDEF to provide a "Tabbed" panel for use in Tab Dialogs
- // : use procID : 109 * 16 + varCode
- // : when calling NewControl() or in your resource template.
- // :
- // : This control can have a maximum of 5 rows of tabs. By default,
- // : there are 4 tabs per row, giving a total of 20 tabs. The
- // : control Max field should contain the number of tabs to draw.
- // :
- // : This default can be changed in 2 ways:
- // :
- // : 1. Display a single row of tabs:
- // :
- // : Variation code 2 will force a single row of tabs, with the
- // : number of tabs specified in the control Max field.
- // :
- // : 2. Increase or decrease the number of tabs per row:
- // :
- // : The LoWord of the control refCon can be used to specify from
- // : 2 to 8 tabs per row. If zero, there will be 4 tabs per row.
- // :
- // : This CDEF supports varCodes of:
- // :
- // : 0 - tab label is Geneva 9, bold for active tab
- // : 1 - tab label is System, underline for active tab
- // : 2 - 1 row of tabs, contrlMax tabs.
- // : 4 - * not used *
- // : 8 - useWindFont for tab label, bold for active tab
- // :
- // : Pretty straight forward code here, only trick here is to use the
- // : contrlMin value as the height of the control. This is done to keep
- // : the Control Manager from thinking the control overlays the controls
- // : you want inside the Panel. Set the real control rect to some value
- // : sufficient to see the title in your resource editor and set contrlMin
- // : to the height of the panel you want drawn.
- // :
- // ** IMPORTANT INFORMATION **
- // :
- // : Since the Control Manager doesn't know about the extra drawing done
- // : by this control, some extra handling is required for update events.
- // : Just calling UpdtControl() will not suffice since there could be a
- // : portion of this control that needs to be drawn that is outside the
- // : "official" control rect.
- // :
- // : So, make sure you call Draw1Control() in response to an update for
- // : any control that uses this CDEF. Calling DrawControls is ok too, but
- // : will draw all of the controls in the window.
- // :
- // : If you find a use for this, I'd love to know about it. Bug reports
- // : are always interesting.
- // :
- // : Internet : JimS@WRQ.COM(work hours, PST)
- // : AppleLink : WRQ (daily)
- // : CompuServe : 73240,2052 (weekly or so)
- // : AOL : JasG (weekly or so)
- // : eWorld : Jim Stout (weekly or so)
- //----------------------------------------------------------------------------------
-
- //#define _DEBUGCDEF 1
-
- #include "fatCDEF.h"
-
- #include <Controls.h>
- #include <LowMem.h>
- #include <Memory.h>
- #include <ToolUtils.h>
- #include <Types.h>
-
- #include "grayCDEF.h"
- #include "colorCDEF.h"
- #include "miscCDEF.h"
-
- #define MAXROWS 5 // maximum number of rows of tabs
- #define MINCOLS 2 // minimum number of tabs per row
- #define MAXCOLS 8 // maximum number of tabs per row
- #define DEFCOLS 4 // default number of tabs per row
- //----------------------------------------------------------------------------------
- // Variation codes
- //----------------------------------------------------------------------------------
-
- #define sysFontTabs 0x0001
- #define oneTabRow 0x0002
- #define useWFont 0x0008 // draw control with window font
-
- //----------------------------------------------------------------------------------
- // CDEF private data
- //----------------------------------------------------------------------------------
- typedef struct {
- short txFont; // font to use for tab labels
- short txSize; // size to use for tab labels
- short cdefHt; // true height of tab panel
- short rowWidth; // width of all tabs on a row
- short rowHt; // height of one tab
- short prevTab; // previously active tab
- short nRows; // number of rows of tabs
- short nCols; // number of tabs in a row
- short rowOrder[MAXROWS];
- short rowChg; // click on back row
- }cdefData,**cdefHandle;
-
- //----------------------------------------------------------------------------------
- // Function prototypes
- //----------------------------------------------------------------------------------
- static void doInit (ControlHandle cHdl, short varCode, short txF, short txS);
- static long doTest (ControlHandle theCtl, long param);
- static void doDraw (ControlHandle cHdl, short varCode);
- pascal void drawControl (short depth, short dFlags, GDHandle theDevice,
- long userData);
- static void drawTitle (ControlHandle cHdl, short varCode, Rect *r,
- Boolean bgInColor, Boolean rowChg,
- short part, short prevTab, short lnHt, short lnAdj);
- static void getNextTitle (Str255 t, Str255 s, short num);
- static short getTabWidth (ControlHandle cHdl, short row);
- static short getMaxCols (ControlHandle cHdl, short row);
-
- #ifdef _DEBUGCDEF
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param);
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
- #else
-
- //==================================================================================
- // CDEF main
- //==================================================================================
-
- pascal long main (short varCode, ControlHandle theCtl, short message, long param)
- #endif
- {
- short txF,txS;
- long ret = 0L;
- Point p;
- GrafPtr thisPort;
- SignedByte cState, dState;
-
- #include "fatEntry.c"
-
- cState = HGetState((Handle)theCtl);
- HLock((Handle)theCtl);
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
-
- GetPort(&thisPort);
-
- //----------------------------------------------------------------------------------
- // set window font & size info
- //----------------------------------------------------------------------------------
-
- txF = thisPort->txFont;
- txS = thisPort->txSize;
- if(varCode & sysFontTabs) { // use system font
- TextFont(LMGetSysFontFam()); // set system as current
- TextSize(LMGetSysFontSize());
- }
- else
- if(!(varCode & useWFont)) { // default to geneva 9
- TextFont(geneva);
- TextSize(9);
- }
-
- //----------------------------------------------------------------------------------
- // Process messages to control
- //----------------------------------------------------------------------------------
-
- switch(message) {
- case initCntl:
- doInit(theCtl, varCode, txF, txS);
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
- break;
- case dispCntl:
- if((**theCtl).contrlData) {
- HUnlock((**theCtl).contrlData);
- DisposeHandle((**theCtl).contrlData);
- (**theCtl).contrlData = 0;
- }
- break;
- case drawCntl:
- if ((**theCtl).contrlVis != 0 &&
- ((WindowPeek)(**theCtl).contrlOwner)->visible) {
- doDraw(theCtl, varCode);
- }
- break;
- case testCntl:
- p.v=HiWord(param);
- p.h=LoWord(param);
- if(PtInRect(p,&(*theCtl)->contrlRect)) {
- ret = doTest(theCtl, param);
- }
- break;
- case calcCRgns:
- RectRgn((RgnHandle)(param & 0x7fffffffL), &(*theCtl)->contrlRect);
- break;
- case calcCntlRgn:
- case calcThumbRgn:
- RectRgn((RgnHandle)(param), &(*theCtl)->contrlRect);
- break;
- }
-
- //----------------------------------------------------------------------------------
- // restore window font & size info
- //----------------------------------------------------------------------------------
-
- if(!(varCode & useWindFont)) {
- TextFont(txF);
- TextSize(txS);
- }
- if((**theCtl).contrlData)
- HSetState((**theCtl).contrlData, dState);
- HSetState((Handle)theCtl, cState);
-
- #include "fatExit.c"
-
- return (ret);
- }
- //==================================================================================
- // Initialize our private control data
- //==================================================================================
- static void doInit(ControlHandle theCtl, short varCode, short txF, short txS)
- {
- cdefHandle hCdef;
- Rect r;
- short wid,ht,notch,rows,maxTabs,maxCols;
-
- hCdef = (cdefHandle)NewHandle(sizeof(cdefData));
- if(hCdef) {
- //----------------------------------------------------------------------------------
- // initialize row order array - this contains the 'order' of the rows which can
- // change in multi-row tab panels.
- //----------------------------------------------------------------------------------
-
- for(rows=1;rows<MAXROWS;rows++)
- (**hCdef).rowOrder[rows-1] = rows;
-
- //----------------------------------------------------------------------------------
- // bounds check on number of columns, rows, control maximum & control value
- //----------------------------------------------------------------------------------
- if(varCode & oneTabRow) {
- maxCols = (**theCtl).contrlMax;
- }
- else {
- maxCols = LoWord((**theCtl).contrlRfCon); // number of columns
- if(maxCols < MINCOLS || maxCols > MAXCOLS) // default to 4
- maxCols = DEFCOLS;
- }
-
- maxTabs = MAXROWS*maxCols;
-
- if((**theCtl).contrlMax <= 0) // should be the total
- (**theCtl).contrlMax = maxCols; // number of tabs
- else
- if((**theCtl).contrlMax > maxTabs)
- (**theCtl).contrlMax = maxTabs;
-
- if((**theCtl).contrlValue > maxTabs) // the 'active' tab
- (**theCtl).contrlValue = 1;
-
- rows = (**theCtl).contrlMax / maxCols;
- if((**theCtl).contrlMax % maxCols) // odd number of tabs,
- rows++; // so add a row
-
- //----------------------------------------------------------------------------------
- // various size limits
- //----------------------------------------------------------------------------------
-
- r = (**theCtl).contrlRect;
- wid = r.right-r.left;
- ht = r.bottom-r.top;
- //----------------------------------------------------------------------------------
- // the "notch" in the right corner must be no more than half the control width
- //----------------------------------------------------------------------------------
-
- notch = HiWord((**theCtl).contrlRfCon);
- if(notch < 0 || notch > wid/2)
- notch = 0;
- //----------------------------------------------------------------------------------
- // width of a row of tabs must be adjusted for 'notch' and a 10 pixel inset
- // from the right edge of control for each row.
- //----------------------------------------------------------------------------------
-
- (**hCdef).rowWidth = wid - notch - ((rows-1)*10);
-
- //----------------------------------------------------------------------------------
- // The height of the control is really in the contrlMin field, not contrlRect
- //----------------------------------------------------------------------------------
-
- (**hCdef).cdefHt = (**theCtl).contrlMin;
- if((**hCdef).cdefHt < ht)
- (**hCdef).cdefHt = 2*ht;
- //----------------------------------------------------------------------------------
- // calcuate the height of one row of tabs
- //----------------------------------------------------------------------------------
- (**hCdef).rowHt = ht / rows;
-
- //----------------------------------------------------------------------------------
- // set rows & columns
- //----------------------------------------------------------------------------------
-
- if(varCode & oneTabRow) { // only want 1 row of tabs
- (**hCdef).nRows = 1;
- (**hCdef).nCols = (**theCtl).contrlMax;
- }
- else {
- (**hCdef).nRows = rows;
- (**hCdef).nCols = maxCols;
- }
-
- (**theCtl).contrlMin = 1;
- (**hCdef).prevTab = 0;
- (**hCdef).txFont = txF;
- (**hCdef).txSize = txS;
-
- (**theCtl).contrlData = (Handle)hCdef;
- }
- }
- //==================================================================================
- // Check for a mouse down in one of our tabs - tab information is stored in the
- // rowOrder.
- //==================================================================================
- static long doTest(ControlHandle theCtl, long param)
- {
- short item,row1,row,col,maxRow,maxCol,tabCnt,tabHt,tabWid;
- Rect r,r2;
- Point p;
- cdefHandle hCdef;
-
- hCdef = (cdefHandle)(**theCtl).contrlData;
- if(!hCdef)
- return 0L;
-
- p.v=HiWord(param);
- p.h=LoWord(param);
-
- tabHt = (**hCdef).rowHt;
- maxRow = (**hCdef).nRows;
- tabCnt = (**theCtl).contrlMax;
- r2 = r = (**theCtl).contrlRect;
-
- for(row=1;row<=maxRow;row++) {
- row1 = (**hCdef).rowOrder[row-1];
- tabWid = getTabWidth(theCtl, row1);
- maxCol = getMaxCols(theCtl, row1);
- r2.right = r2.left+tabWid;
- r2.top = r2.bottom-tabHt;
- r = r2;
- for(col=1;col<=maxCol;col++) {
- item = (row1-1)*(**hCdef).nCols + col;
- if(item > tabCnt)
- break;
- if(PtInRect(p, &r)) {
- while(StillDown()) {}
- GetMouse(&p);
- if(PtInRect(p,&r))
- return((long)item);
- else
- return (0L);
- }
- OffsetRect(&r,tabWid-1, 0);
- }
- OffsetRect(&r2, 10, -tabHt);
- }
- return (0L);
- }
- //==================================================================================
- // If running with System 7, use DeviceLoop to gracefully handle multiple screens.
- // Simulate DeviceLoop if using System 6...
- //==================================================================================
-
- static void doDraw(ControlHandle theCtl, short varCode)
- {
- devLoopHandle hDl;
- cdefHandle hCdef;
- short newRow,inx,row,maxRow;
- Rect fullRect;
- RgnHandle saveClip, hRgn;
- DeviceLoopDrawingUPP drawControlUPP;
-
- hCdef = (cdefHandle)(**theCtl).contrlData;
- if(!hCdef)
- return;
-
- //----------------------------------------------------------------------------------
- // if called to Hilite the control, just set the control value and leave
- // because we don't hilite.
- //----------------------------------------------------------------------------------
-
- if((**theCtl).contrlHilite == 0xFF)
- return;
-
- if((**theCtl).contrlHilite) {
- (**theCtl).contrlValue = (**theCtl).contrlHilite;
- return;
- }
-
- //----------------------------------------------------------------------------------
- // Setup our userData to pass via DeviceLoop
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)NewHandle(sizeof(devLoopData));
- if(hDl) {
- drawControlUPP = NewDeviceLoopDrawingProc(drawControl);
-
- (**hDl).theCtl = theCtl;
- (**hDl).varCode = varCode;
-
- fullRect = (**theCtl).contrlRect;
- fullRect.bottom = fullRect.top + (**hCdef).cdefHt;
-
- (**hDl).controlRect = fullRect;
-
- //----------------------------------------------------------------------------------
- // Set clip region for the full panel, not just what the control mgr thinks it is
- //----------------------------------------------------------------------------------
-
- saveClip = NewRgn();
- GetClip(saveClip);
-
- hRgn = NewRgn();
- RectRgn(hRgn, &fullRect);
- SectRgn(saveClip, hRgn, hRgn);
-
- //----------------------------------------------------------------------------------
- // adjust the rowOrder if needed (user clicked on row other than lowest)
- //----------------------------------------------------------------------------------
-
- newRow = ((**theCtl).contrlValue-1) / (**hCdef).nCols + 1;
-
- if(newRow != (**hCdef).rowOrder[0]) {
- (**hCdef).rowChg = true;
- (**hCdef).rowOrder[0] = newRow;
-
- maxRow = (**hCdef).nRows;
- row = 0;
- for(inx=1;inx<=maxRow-1;inx++) {
- row++;
- if(row == newRow)
- row++;
- (**hCdef).rowOrder[inx] = row;
- }
- }
- else
- (**hCdef).rowChg = false;
-
- //----------------------------------------------------------------------------------
- // Let DeviceLoop call our drawing routine for us
- //----------------------------------------------------------------------------------
-
- if(getOSVers() >= 0x0700) {
- DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
- else {
- sys6DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
-
- SetClip(saveClip);
- DisposeRgn(hRgn);
- DisposeHandle((Handle)hDl);
- DisposeRoutineDescriptor(drawControlUPP);
- (**hCdef).prevTab = (**theCtl).contrlValue;
- }
- }
- //==================================================================================
- // draw the tab panel. Lots and lots of tedious line drawing - all done onscreen,
- // no real need for offscreen drawing.
- //==================================================================================
- pascal void drawControl (short depth, short dFlags, GDHandle theDevice, long userData)
- {
-
- #pragma unused(dFlags, theDevice)
-
- ControlHandle theCtl;
- GrafPtr thisPort;
- short varCode,tabWidth,tabHt,notch,rightEdge,bottomEdge;
- short inx,row,maxRow,col,maxCol,pLeft;
- short tabCnt,activeTab,currTab,prevTab;
- short lnHt,lnAdj;
- Rect panel,tab,fullRect,edgeRect,allTabs;
- FontInfo f;
- PenState savePen;
- RGBColor rgbGray,rgbGrayLt,saveFore,saveBack;
- Boolean inColor = false, bgInColor = false;
- Boolean partialRow = false;
-
- cdefHandle hCdef; // our private data structures
- devLoopHandle hDl;
-
- //----------------------------------------------------------------------------------
- // Can we draw?
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)userData; // need control & varCode
- if(hDl) {
- theCtl = (**hDl).theCtl;
- varCode = (**hDl).varCode;
- }
- else
- return;
-
- hCdef = (cdefHandle)(**theCtl).contrlData;
- if(!hCdef)
- return;
-
- //----------------------------------------------------------------------------------
- // initialize for drawing
- //----------------------------------------------------------------------------------
- GetPort(&thisPort);
- if(depth > 1 && !(((CGrafPtr)thisPort)->portVersion & 0x8000))
- depth = 1;
-
- prevTab = (**hCdef).prevTab;
- activeTab = (**theCtl).contrlValue;
- tabCnt = (**theCtl).contrlMax;
- tabHt = (**hCdef).rowHt;
- maxRow = (**hCdef).nRows;
-
- if(maxRow != (tabCnt / (**hCdef).nCols)) // last row partial?
- partialRow = true;
-
- //----------------------------------------------------------------------------------
- // get the font info for drawing title
- //----------------------------------------------------------------------------------
-
- GetFontInfo(&f);
- lnAdj = f.descent + f.leading;
- lnHt = f.ascent + lnAdj;
- GetPenState(&savePen);
- PenSize(1,1);
- PenPat( (ConstPatternParam) "\xff\xff\xff\xff\xff\xff\xff\xff");
-
- //----------------------------------------------------------------------------------
- // get the true Rect for the control
- //----------------------------------------------------------------------------------
-
- panel = tab = (**theCtl).contrlRect;
- panel.bottom = panel.top + (**hCdef).cdefHt;
- fullRect = panel;
- panel.right = panel.right-((maxRow-1) * 10);
-
- //----------------------------------------------------------------------------------
- // get color information and set flags for color/3D drawing
- //----------------------------------------------------------------------------------
-
- if(depth > 2) {
- saveColors(&saveFore, &saveBack);
- setPartColor(theCtl, cFrameColor, true);
-
- if(getGray(&rgbGray)) { // get the 2 grays we will
- RGBForeColor(&rgbGray); // use for shading the right
- getGray(&rgbGrayLt); // and bottom edges.
- }
- else {
- rgbGray.red = rgbGray.green = rgbGray.blue = 0x8888;
- rgbGrayLt.red = rgbGrayLt.green = rgbGrayLt.blue = 0xCCCC;
- }
-
- inColor = true;
- bgInColor = true;
- if(saveBack.red == 65535 && // is bg white?
- saveBack.green == 65535 &&
- saveBack.blue == 65535)
- bgInColor = false;
- }
-
- //----------------------------------------------------------------------------------
- // Draw each tab by looping thru rows (by rowOrder[]) & columns
- //----------------------------------------------------------------------------------
-
- for(inx=1;inx<=maxRow;inx++) {
- row = (**hCdef).rowOrder[inx-1];
-
- tabWidth = getTabWidth(theCtl, row); // may be different
- tab.right = tab.left+tabWidth; // for some rows
- tab.top = tab.bottom - tabHt;
-
- bottomEdge = tab.bottom;
- rightEdge = panel.left + (**hCdef).rowWidth;
- notch = panel.right - rightEdge;
-
- if((**hCdef).rowChg && partialRow) { // clear old tabs
- allTabs = tab;
- allTabs.right = rightEdge-4;
- allTabs.left+=4;
- EraseRect(&allTabs);
- }
-
- maxCol = getMaxCols(theCtl, row);
-
- for(col=1;col<=maxCol;col++) {
- currTab = (**hCdef).nCols * (row-1) + col;
- if(currTab > tabCnt)
- break;
- if(col == maxCol) // last tab must
- tab.right = rightEdge; // fill control rect
-
- //----------------------------------------------------------------------------------
- // draw the tab title
- //----------------------------------------------------------------------------------
-
- if(inColor)
- setPartColor(theCtl, cTextColor, true);
- drawTitle (theCtl, varCode, &tab, bgInColor, (**hCdef).rowChg,
- currTab, prevTab, lnHt, lnAdj);
-
- if(inColor) {
-
- //----------------------------------------------------------------------------------
- // draw white shadow along left & top inside edges of tab
- //----------------------------------------------------------------------------------
-
- ForeColor(whiteColor);
- MoveTo(tab.left+1,tab.bottom-1);
- if(currTab == activeTab)
- Move(0,1);
- LineTo(tab.left+1,tab.top+3); // left edge
- LineTo(tab.left+3,tab.top+1); // left corner
- LineTo(tab.right-5,tab.top+1); // top edge
- if(currTab == activeTab) {
- Move(1,1);
- LineTo(tab.left+2, tab.top+2);
- LineTo(tab.left+2, tab.bottom+1);
- }
-
- //----------------------------------------------------------------------------------
- // draw white shadow on top edge of front panel (this is the bottom edge of tabs)
- // lots of work to avoid flicker...
- //----------------------------------------------------------------------------------
-
- if(inx == 1) {
-
- if(currTab != activeTab) {
- ForeColor(whiteColor);
- MoveTo(tab.left,tab.bottom+1);
- if(col == 1)
- Move(3,0);
- else
- Move(-1,0);
- if(col == maxCol) {
- LineTo(tab.right-3,tab.bottom+1);
- Move(-1,0);
- }
- else
- LineTo(tab.right,tab.bottom+1);
- Move(0,1);
- if(col == 1)
- LineTo(tab.left+3,tab.bottom+2);
- else
- LineTo(tab.left-2,tab.bottom+2);
- }
- }
-
- //----------------------------------------------------------------------------------
- // draw gray shadow along right edge of tab
- //----------------------------------------------------------------------------------
-
- RGBForeColor(&rgbGray);
- MoveTo(tab.right-4, tab.top+1);
- LineTo(tab.right-2, tab.top+3); // right corner
- if(currTab == activeTab) {
- LineTo(tab.right-2, tab.bottom); // right edge
- if(bgInColor)
- Move(-1,1);
- else
- Move(-1,0);
- RGBForeColor(&rgbGrayLt);
- LineTo(tab.right-3, tab.top+3);
- }
- else
- LineTo(tab.right-2, tab.bottom-1);
- if(col == maxCol && inx != 1)
- Line(0,2);
- }
-
- //----------------------------------------------------------------------------------
- // draw the tab frame
- //----------------------------------------------------------------------------------
-
- if(inColor)
- setPartColor(theCtl, cFrameColor, true);
- MoveTo(tab.left,tab.bottom);
- LineTo(tab.left,tab.top+3); // left edge
- LineTo(tab.left+3,tab.top); // left corner
- LineTo(tab.right-4,tab.top); // top edge
- LineTo(tab.right-1,tab.top+3); // right corner
- LineTo(tab.right-1,tab.bottom); // right edge
-
- MoveTo(tab.right-2,tab.bottom);
- if(currTab != activeTab && inx == 1) // bottom edge needed
- LineTo(tab.left,tab.bottom);
- else
- if(inx == 1) { // bottom edge not needed
- edgeRect = tab;
- edgeRect.left++;
- edgeRect.right--;
- edgeRect.top = edgeRect.bottom++;
- if(inColor) { // erase to bg color
- RGBForeColor(&saveBack);
- edgeRect.left+=2;
- edgeRect.right-=2;
- }
- EraseRect(&edgeRect);
- }
- OffsetRect(&tab,tabWidth-1, 0); // next tab to draw
- }
-
- //----------------------------------------------------------------------------------
- // draw panel outline
- //----------------------------------------------------------------------------------
-
- if(inColor)
- setPartColor(theCtl, cFrameColor, true);
-
- if(inx == 1) { // first panel
- pLeft = panel.left;
- MoveTo(pLeft,bottomEdge);
- LineTo(pLeft,panel.bottom-1); // left edge
- }
- else
- pLeft = panel.right-10;
- MoveTo(pLeft,panel.bottom-1);
- LineTo(panel.right-1,panel.bottom-1); // bottom edge
- LineTo(panel.right-1,bottomEdge); // right edge
-
- if(notch) { // top edge (if needed)
- Line(-notch,0);
- }
-
- //----------------------------------------------------------------------------------
- // draw panel shadowing inside panel frame
- //----------------------------------------------------------------------------------
-
- if(inColor) {
-
- //----------------------------------------------------------------------------------
- // draw white shadow along left edge of panel
- //----------------------------------------------------------------------------------
-
- ForeColor(whiteColor);
- PenSize(2,2);
- if(inx == 1) {
- MoveTo(pLeft+1,bottomEdge+1);
- LineTo(pLeft+1,panel.bottom-3);
- }
- PenSize(1,1);
-
- //----------------------------------------------------------------------------------
- // draw white shadow along top edge of panel
- //----------------------------------------------------------------------------------
-
- if(notch) {
- MoveTo(panel.right-3,bottomEdge+1);
- Line(-notch+1,0);
- if(inx == 1) {
- Move(-1,1);
- Line(notch-1,0);
- }
- }
-
- //----------------------------------------------------------------------------------
- // draw gray shadow along bottom edge of panel
- //----------------------------------------------------------------------------------
-
- RGBForeColor(&rgbGrayLt);
- PenSize(1,1);
- MoveTo(panel.right-3, panel.bottom-3);
- if(inx == 1) { // first panel
- LineTo(pLeft+3,panel.bottom-3);
- Move(-1,1);
- }
- else
- MoveTo(pLeft,panel.bottom-2);
- RGBForeColor(&rgbGray);
- LineTo(panel.right-2, panel.bottom-2);
-
- //----------------------------------------------------------------------------------
- // draw gray shadow along right edge of panel
- //----------------------------------------------------------------------------------
-
- if(inx == 1 || notch) { // first panel
- LineTo(panel.right-2, bottomEdge+1);
- if(bgInColor)
- Move(-1,1);
- else
- Move(-1,0);
- }
- else {
- LineTo(panel.right-2, tab.top+3);
- Move(-1,0);
- }
- RGBForeColor(&rgbGrayLt);
- if(inx == 1)
- LineTo(panel.right-3, panel.bottom-3);
- }
-
- //----------------------------------------------------------------------------------
- // prepare to draw the next panel
- //----------------------------------------------------------------------------------
-
- OffsetRect(&panel, 10, 0); // draw next panel, which
- panel.bottom-=10; // is shifted up & right
- OffsetRect(&tab, 0, -tabHt); // shift tab up to next row
- tab.left = panel.left;
- }
-
- if(inColor)
- restoreColors(&saveFore, &saveBack);
- SetPenState(&savePen);
- }
-
- //==================================================================================
- // draw the titles for the tabs. Must take care of redrawing a previous tab in
- // a normal face and active tab in a bold face.
- //==================================================================================
- static void drawTitle (ControlHandle theCtl, short varCode, Rect *r,
- Boolean bgInColor, Boolean rowChg,
- short part, short prevTab,
- short lnHt, short lnAdj)
- {
- short lnCnt=1,ctlSpace,v,h;
- Str255 s;
- RgnHandle saveClip;
- Rect tRect;
- RGBColor saveFore;
-
- //----------------------------------------------------------------------------------
- // clear title area if needed - click on new tab or we are swapping rows around
- //----------------------------------------------------------------------------------
-
- if(part == prevTab || part == (**theCtl).contrlValue || rowChg) {
- tRect = *r;
- InsetRect(&tRect, 2, 2);
- if( part == (**theCtl).contrlValue)
- tRect.bottom+=5;
- else
- tRect.bottom+=2;
- EraseRect(&tRect);
- }
-
- getNextTitle((*theCtl)->contrlTitle, s, part);
- if(s[0]) { // is there a title?
-
- saveClip = NewRgn();
- GetClip(saveClip);
-
- if(bgInColor)
- GetForeColor(&saveFore);
-
- if(part == (**theCtl).contrlValue) {
- if(varCode & sysFontTabs)
- TextFace(underline);
- else
- TextFace(bold);
- }
- v = (*r).bottom; // baseline
- ctlSpace = (*r).bottom - (*r).top; // available height
- v-=(ctlSpace - lnHt)/2; // minus free space
- v-=lnAdj; // minus descent+leading
-
- h = (*r).left + ((*r).right - (*r).left - StringWidth(s))/2;
-
- ClipRect(r);
-
- if(bgInColor) { // draw 3D title
- ForeColor(whiteColor);
- MoveTo(h+1, v+1);
- DrawString(s);
- RGBForeColor(&saveFore);
- }
- MoveTo(h, v);
- DrawString(s);
-
- TextFace(normal); // cleanup & leave
- SetClip(saveClip);
- }
- }
- //==================================================================================
- // Grab the next tab title from the control title (assumes lines separated by CR)
- //==================================================================================
- static void getNextTitle(Str255 t, Str255 s, short part)
- {
- short inx=1,len=0,tCnt=1;
-
- s[0] = 0; // always default to null string
-
- do {
- if(t[inx] == 0x0d) // next title
- tCnt++;
- else
- if(tCnt == part) { // return this title
- len++;
- s[0] = len;
- s[len] = t[inx];
- }
- inx++;
- }while (inx <= t[0]);
- }
- //==================================================================================
- // calculate the maximum number of columns in this row of tabs
- //==================================================================================
-
- static short getMaxCols (ControlHandle theCtl, short row)
- {
- short tabCnt;
- cdefHandle hCdef;
-
- hCdef = (cdefHandle)(**theCtl).contrlData;
- if(!hCdef)
- return 0;
-
- if(row == (**hCdef).nRows) // last row
- tabCnt = (**theCtl).contrlMax - ((**hCdef).nCols * (row -1));
- else
- tabCnt = (**hCdef).nCols;
- return(tabCnt);
- }
- //==================================================================================
- // calculate the width of a single tab - can be different for last row if it is not
- // a complete row.
- //==================================================================================
-
- static short getTabWidth(ControlHandle theCtl, short row)
- {
- short wid,tabWidth,temp,tabCnt;
- cdefHandle hCdef;
-
- hCdef = (cdefHandle)(**theCtl).contrlData;
- if(!hCdef)
- return 0;
-
- if(row == (**hCdef).nRows) // last row
- tabCnt = (**theCtl).contrlMax - ((**hCdef).nCols * (row -1));
- else
- tabCnt = (**hCdef).nCols;
-
-
- wid = (**hCdef).rowWidth;
-
- tabWidth = wid/tabCnt; // width of 1 tab
-
- temp = wid - (tabWidth-1)*tabCnt; // round it up a bit
- tabWidth = tabWidth + temp/tabCnt;
-
- return(tabWidth);
- }